/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.erpnasajon.seguranca;

/**
 *
 * @author RafaMend
 */
public class Codificar {

    static final double def_p = 13;
    static final double def_q = 17;
    static final double def_e = 5;
    static final boolean def_auto = true;
    
    private String entrada;
    private double primo_P;
    private double primo_Q;
    private boolean auto_set;
    private double num_E;

    private double elevar_mod(double base, double expoente, double n) {
        double i = 0;
        double valor = 1;
        while (i != expoente) {
            valor = valor * base;
            valor = modReal(valor, n);
            i = i + 1;
        }
        return valor;
    }

    private double Fi_N(double p, double q) {
        return (p - 1) * (q - 1);
    }

    private double achar_e(double p, double q) {
        //inicialização
        double retorno = 0;
        double e = 2;
        boolean teste = true;
        double fin = Fi_N(p, q);
        double i;
        while (e < fin) {
            i = 2;
            while (i <= e) {
                if ((modReal(e, i) == 0) && (modReal(fin, i) == 0)) {
                    teste = false;
                    break;
                }
                i = i + 1;
            }
            if (teste) {
                retorno = e;
                break;
            } else {
                e = e + 1;
                teste = true;
            }
        }
        return retorno;
    }

    private double modReal(double numero, double classe) {
        double divisao = Math.round(Math.floor(numero / classe)); //estava Int
        return numero - (divisao * classe);
    }

    private boolean testprimo(double numero) {
        double i = 1;
        boolean retorno = true;
        while (i != numero) {
            if ((i != 1) && (i != numero)) {
                if (modReal(numero, i) == 0) {
                    retorno = false;
                    i = (i + 1);
                } else {
                    i = (i + 1);
                }
            } else {
                i = (i + 1);
            }
        }
        return retorno;
    }

    public String codificar() {
        //codificar
        //precodifica
        String precod = "";
        char[] texto = this.entrada.toCharArray();
        for (int i = 0; i < texto.length; i++) {
            precod = precod + Integer.toString((int) texto[i] + 1000);
        }
        //inicialização
        String bloco = "";
        String saida = "";
        int i = 0;
        //codificação
        char[] texto2 = precod.toCharArray();
        while (i <= (texto2.length-1)) {
            bloco = bloco + texto2[i]; //soma letra ao bloco
            // Se número no bloco maior que 50 e menor que N, e ou o proximo não é zero ou e o final
            if ((Integer.parseInt(bloco) >= 50)
                    && (Integer.parseInt(bloco) < (this.primo_P * this.primo_Q))
                    && ( (i == (texto2.length-1)) || (!"0".equals(String.valueOf(texto2[i+1]))))) {
                double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                saida = saida + bloco + '-';
                bloco = "";
                i++;
            } //se e maior que 50 e menor que n mais o proximo e 0
            else if ((Integer.parseInt(bloco) >= 50)
                    && (Integer.parseInt(bloco) < (this.primo_P * this.primo_Q))
                    && ("0".equals(String.valueOf(texto2[i+1])))) {
                if ("0".equals(String.valueOf(texto2[i]))) {
                    bloco = bloco.substring(0, bloco.length() - 2);
                    double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                    bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                    saida = saida + bloco + '-';
                    i--;
                    bloco = "";
                } else {
                    bloco = bloco.substring(0, bloco.length() - 1);
                    double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                    bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                    saida = saida + bloco + '-';
                    bloco = "";
                }
            } //se e menor que 50 e é o final
            else if ((Integer.parseInt(bloco) < 50) && (i == (texto2.length-1))) {
                double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                saida = saida + bloco + '-';
                bloco = "";
                i++;
            } //se e menor que 50 e o proximo for 0
            else if ((Integer.parseInt(bloco) < 50) && ("0".equals(String.valueOf(texto2[i + 1])))) {
                if ((Integer.parseInt(bloco) * 10) >= (this.primo_P * this.primo_Q)) {
                    if ("0".equals(String.valueOf(texto2[i]))) {
                        bloco = bloco.substring(0, bloco.length() - 1);
                        double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                        bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                        saida = saida + bloco + '-';
                        bloco = "00";
                        saida = saida + bloco + '-';
                        i += 2;
                        bloco = "";
                    } else {
                        bloco = bloco.substring(0, bloco.length() - 1);
                        double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                        bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                        saida = saida + bloco + '-';
                        bloco = "";
                    }
                } //se não for nenhum desses
                else {
                    i++;
                }
            } //se e maior que N
            else if (Integer.parseInt(bloco) >= (this.primo_P * this.primo_Q)) {
                bloco = bloco.substring(0, bloco.length() - 1);
                double elev_mod = elevar_mod(Double.parseDouble(bloco), this.num_E, (this.primo_P * this.primo_Q));
                bloco = String.valueOf(Math.round(Math.floor(elev_mod))); //estava Int
                saida = saida + bloco + '-';
                bloco = "";
            } //se for nenhum desses
            else {
                i++;
            }
        }
        return saida;
    }

    public Codificar(String entrada) {
        this.setPrimo_P(def_p); 
        this.setPrimo_Q(def_q);
        this.setNum_E(def_e);
        this.setAuto_set(def_auto);
        this.setEntrada(entrada);
    }

    /**
     * @return the entrada
     */
    public String getEntrada() {
        return entrada;
    }

    /**
     * @param entrada the entrada to set
     */
    public void setEntrada(String entrada) {
        this.entrada = entrada;
    }

    /**
     * @return the primo_P
     */
    public double getPrimo_P() {
        return primo_P;
    }

    /**
     * @param primo_P the primo_P to set
     */
    public void setPrimo_P(double primo_P) {
        if ((primo_P * this.getPrimo_Q()) < (1.1 * Math.pow(10, 4932))) {
            if (testprimo(primo_P)) {
                this.primo_P = primo_P;
            } else {
                System.err.println("O número colocado não é primo em P!");
            }
        } else {
            System.err.println("O número N=Pxq é muito grande!");
        }
    }

    /**
     * @return the primo_q
     */
    public double getPrimo_Q() {
        return primo_Q;
    }

    /**
     * @param primo_q the primo_q to set
     */
    public void setPrimo_Q(double primo_Q) {
        if ((primo_Q * this.getPrimo_P()) < (1.1 * Math.pow(10, 4932))) {
            if (testprimo(primo_Q)) {
                this.primo_Q = primo_Q;
            } else {
                System.err.println("O número colocado não é primo em q!");
            }
        } else {
            System.err.println("O número N=Pxq é muito grande!");
        }
    }

    /**
     * @return the auto_set
     */
    public boolean isAuto_set() {
        return auto_set;
    }

    /**
     * @param auto_set the auto_set to set
     */
    public void setAuto_set(boolean auto_set) {
        this.auto_set = auto_set;
    }

    /**
     * @return the num_E
     */
    public double getNum_E() {
        return num_E;
    }

    /**
     * @param num_E the num_E to set
     */
    public void setNum_E(double num_E) {
        if (num_E < (this.primo_P * this.primo_Q)) {
            if (this.auto_set) {
                this.num_E = achar_e(this.primo_P, this.primo_Q);
            } else {
                this.num_E = num_E;
            }
        } else {
            System.err.println("E é maior que N=P*Q!");
        }

    }
}
